package world0;

import java.util.ArrayList;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Shape;

public abstract class GameObject {
	
	protected float x;
	protected float y;
	protected Image image;

	protected int state;
	
	/* Walking Variabels */
	
	private int upDown;
	private boolean isMove = false;
	private float saveX;
	private boolean isSaveXOn = false;
	private boolean isWalkLeft = false;
	private boolean isWalkRight = false;
	private boolean isRandomWalk = false;
	private boolean isFallAllow = true;
	private boolean isFall = true;
	private float fallSpeed;
	
	private boolean isJump = false;
	private boolean isJumpSaved = false;
	private float savedYJump;
	private int maxJump = 100;
	
	private float startSpeed;
	private float speedResetValue;
	private float accelration;
	
	private ArrayList<LevelObject> solidList;
	private ArrayList<LevelObject> slopeList;
	
	protected CollisionDetection collision;
	
	//private Shape collisionArea;

	public abstract void draw(Graphics g) throws SlickException;

	/* Kill this - State DEPRECATED*/
	public GameObject(float x, float y, Image image, int state) {
		this.x = x;
		this.y = y;
		this.image = image;
		this.state = state;

		collision = new CollisionDetection(x, y, image, state);

	}
	
	public GameObject(float x, float y, Image image, int state, int upDown) {
		this.x = x;
		this.y = y;
		this.image = image;
		this.state = state;
		this.upDown = upDown;

		collision = new CollisionDetection(x, y, image, state, upDown);
	}
	
	public GameObject(float x, float y, Image image) {
		this.x = x;
		this.y = y;
		this.image = image;

	}
	
	public GameObject(float x, float y) {
		this.x = x;
		this.y = y;
	}

	public GameObject(Image image) {
		this.image = image;
	}

	public GameObject(int state) {
		this.state = state;
	}
	
	/* Moving */
	
	public void bodyFall(float speed, float fallSpeed, ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		
		/* Collision behavior OLD WORKING STYLE */
		
		
		/* Move on fall */
		if(isFall) {
			y += fallSpeed;
		}
		
		/* If hitting something fall down */
		if(isJump && collision.sideCheckCollisionLevelObject(solidList, "Top")) {
			isFall = true;
			isJump = false;
		}
		
		/* If nothing hit (air) fall down */
		if(!collision.sideCheckCollisionLevelObject(solidList, "Top") && !isJump) {
			isFall = true;
		}
		
		/* After hitting ground stop fall */
		if(!isJump && collision.sideCheckCollisionLevelObject(solidList, "Buttom") || collision.checkCollisionSlope(slopeList)) {
			isFall = false;
			isJumpSaved = false;
		}
	}
	
	public void randomWalk(ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		this.solidList = solidList;
		this.slopeList = slopeList;
		isRandomWalk = true;
		
		if(!isMove) {
			isMove = true;
			int randomNumber = 0;//(int) (Math.random() * 2);
			
			if(randomNumber == 0) {
				isWalkLeft = true;
			} else {
				isWalkRight = true;
			}
		}
	}
	
	public void jump(float fallSpeed, int maxJump, ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		collision.update(getX(), getY());
		this.fallSpeed = fallSpeed;
		if(!isFall) {
			isJump = true;
			setY(getY() - fallSpeed - 0.3f);
			
			/* Get start Y value and dont override after next frame */
			if(!isJumpSaved) {
				savedYJump = getY();
				isJumpSaved = true;
			}
		}
		if(getY() <= savedYJump - maxJump && isJump) {
			isFall = true;
			isJump = false;
		}
	}
	
	public void walk(int randomWalkRadius, float speed) {
		
		/* Left Walking */
		if(isWalkLeft) {
			if(isRandomWalk) {
				if(!isSaveXOn) {
					saveX = x;
					isSaveXOn = true;
				}
				
				if(((saveX - randomWalkRadius) <= x) && !collision.sideCheckCollisionLevelObject(solidList, "Left")) {
					x -= speed;
					if(collision.checkCollisionSlope(slopeList)) {
						isFallAllow = false;
						y -= speed;
					} else {
						isFallAllow = true;
					}
				} else {
					isWalkLeft = false;
					isWalkRight = true;
					isSaveXOn = false;
				}
			} else {
				/* Standard Walk Left */
			}
		}
		
		/* Right Walking */
		if(isWalkRight) {
			if(isRandomWalk) {
				if(!isSaveXOn) {
					saveX = x;
					isSaveXOn = true;
				}
				
				if(((randomWalkRadius + saveX) >= x) && !collision.sideCheckCollisionLevelObject(solidList, "Right")) {
					x += speed;
					if(collision.checkCollisionSlope(slopeList)) {
						isFallAllow = false;
						y -= speed;
					} else {
						isFallAllow = true;
					}
				} else {
					isWalkRight = false;
					isWalkLeft = true;
					isSaveXOn = false;
				}
			} else {
				/* Standard Walk Right */
			}
		}
	}
	
	public void moveLeft(float speed, ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		
		collision.update(getX(), getY());
		
		if(!collision.sideCheckCollisionLevelObject(solidList, "Left")) {
			if (startSpeed < speed) {
				startSpeed += accelration;
			}
			setX(getX() - speed);
			
			if(collision.checkCollisionSlope(slopeList)) {
				setY(getY() - speed);
				isFallAllow = false;
			}
		}
	}
	
	public void moveRight(float speed, ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		collision.update(getX(), getY());
		if(!collision.sideCheckCollisionLevelObject(solidList, "Right")) {
			if (startSpeed < speed) {
				startSpeed += accelration;
			}
			setX(getX() + startSpeed);
			
			if(collision.checkCollisionSlope(slopeList)) {
				setY(getY() - speed);
				isFallAllow = false;
			}
		}
	}
	
	public void resetSpeed(float speed) {
		if(startSpeed >=  speed / speedResetValue) {
			startSpeed -= 0.01f;
		}
	}
	
	public void update(float speed, ArrayList<LevelObject> solidList, ArrayList<LevelObject> slopeList) {
		collision.update(getX(), getY());
		
		if(isJump) {
			jump(speed, maxJump, solidList, slopeList);
		}
		
		/* Debug: stucked @ corner */
		if(collision.debugCheckCollisionLevelObject(solidList)) {
			isFall = false;
			setY(getY() - 1f);
		}
	}
	
	public float getSpeedResetValue() {
		return speedResetValue;
	}

	public void setSpeedResetValue(float speedResetValue) {
		this.speedResetValue = speedResetValue;
	}

	public boolean isFall() {
		return isFall;
	}

	public void setFall(boolean isFall) {
		this.isFall = isFall;
	}

	public boolean isJump() {
		return isJump;
	}

	public void setJump(boolean isJump) {
		this.isJump = isJump;
	}

	public Image getImage() {
		return image;
	}
	
	public int getSlopeUpDown() {
		return this.upDown;
	}

	public float getX() {
		return x;
	}

	public void setX(float x) {
		this.x = x;
	}

	public float getY() {
		return y;
	}

	public void setY(float y) {
		this.y = y;
	}

	public int getImageHeight() {
		return image.getHeight();
	}
	
	public int getImageWidth() {
		return image.getWidth();
	}

	public boolean checkCollision(Shape shape) {
		return checkCollision(shape);
	}
	
	public float getStartSpeed() {
		return startSpeed;
	}

	public void setStartSpeed(float startSpeed) {
		this.startSpeed = startSpeed;
	}
	
	public float getAccelration() {
		return accelration;
	}

	public void setAccelration(float accelration) {
		this.accelration = accelration;
	}
	
	/* DEPERCATED */
	public Shape getShape() {
		return collision.getShapeArea();
	}
	
	public int getState() {
		return this.state;
	}
	
	/* DEPRECATED use super.collision.check...  
	public boolean checkCollisonLevelObject(Shape collisionArea, ArrayList<LevelObject> solidList) {
		return collision.checkCollisonLevelObject(collisionArea, solidList); 
	}
	
	public boolean checkCollisonLevelObjectNonCloud(Shape collisionArea, ArrayList<LevelObject> solidList) {
		return collision.checkCollisonLevelObjectNonCloud(collisionArea, solidList); 
	}
	
	public boolean checkCollisonLevelObject(Shape collisionArea, ArrayList<LevelObject> solidList, int state) {
		return collision.checkCollisonLevelObject(collisionArea, solidList, state); 
	}
	
	public boolean checkCollisionMob(Shape collisionArea, ArrayList<Mob> mobList) {
		return collision.checkCollisionMob(collisionArea, mobList); 
	}
	
	
	public boolean checkCollisionMobDmg(Shape collisionArea, ArrayList<Mob> mobList) {
		return collision.checkCollisionMobDmg(collisionArea, mobList); 
	}
	
	public boolean checkSlope(Shape collisionArea, ArrayList<LevelObject> solidList) {
		return collision.checkSlope(collisionArea, solidList);
	}
	/* DEPRECATED - END -----*/
}
